import chokidar, { watch } from 'chokidar';
import fs from 'fs';
class Watch{
    rootPath:string
    private static hot: Watch = new Watch();
    private list: Set<string>
    private watch: any
    private checkPath: string | null = null
    stopHandler: any = ()=>{}

    private constructor(){
        console.log(`\n\n \x1b[32m hot start \x1b[0m \n\n`);
        this.rootPath = process.cwd()
        this.list = new Set<string>();
    }

    // 检查
    private watchInstance(checkPath: string | null = null){
        if(this.watch != null){
            this.watch.close();
        }
        checkPath = checkPath == null ? this.rootPath+'/src' : checkPath;
        console.log(`\n\n\t  \x1b[32m watch path : ${checkPath} \x1b[0m \n\n`);
        this.watch = chokidar.watch(checkPath).on('all', (event, path, stats) => {
            if(event == 'add' && stats.isFile() && path.endsWith(".ts") && path != process.argv[1] && !path.endsWith('.d.ts')){
                this.list.add(path);
            }
            if(event == 'change' && stats.isFile && !path.endsWith('.d.ts') && path.endsWith(".ts")){
                let isSuccess = true;
                this.unmount(process.argv[1]);
                if(path != process.argv[1]){
                    this.unmount(path);
                    if(!this.mount(path))
                        return;
                }

                let list = [];
                this.list.forEach( file=> { if(this.reloadMode(file))list.push(file); });
                list.forEach(file=>{this.unmount(file)});
                list.forEach(file=>{ if(isSuccess && !this.mount(file)) isSuccess = false; });
                if(!isSuccess){
                    return ;
                }

                this.stopHandler();
                this.mount(process.argv[1]);
            }
        });
    }

    static getInstance(stopHandler: any, checkPath: string|null = null): Watch{
        if(checkPath != null ){
            if(checkPath.startsWith('.')){
                checkPath = Watch.hot.rootPath + checkPath.substring(1);
                if(!fs.existsSync(checkPath)){
                    console.log(`\t \x1b[31m watch.getInstance argument 2 !  Directory : ${checkPath}  not exist \x1b[0m \n`);
                    checkPath = null;
                }
            }else if(checkPath[0] != '/'){
                if(fs.existsSync(Watch.hot.rootPath +"/"+ checkPath)){
                    checkPath = Watch.hot.rootPath + checkPath;
                }else if(!fs.existsSync(checkPath)){
                    console.log(`\t \x1b[31m watch.getInstance argument 2 !  Directory : ${checkPath}  not exist \x1b[0m \n`);
                    checkPath = null;
                }
            }else if(!fs.existsSync(checkPath)){
                console.log(`\t \x1b[31m watch.getInstance argument 2 !  Directory : ${checkPath}  not exist \x1b[0m \n`);
                checkPath = null;
            }
        }
        
        if(Watch.hot.watch == null){
            Watch.hot.watchInstance(null);
        }else if(checkPath != Watch.hot.checkPath){
            Watch.hot.checkPath = checkPath;
            Watch.hot.watchInstance(checkPath);
        }
        Watch.hot.watch
        Watch.hot.stopHandler = stopHandler;
        return Watch.hot;
    }
    reloadMode(file: string):boolean{
        return false;
    }
    private unmount(model: string){
        try{
            delete require.cache[require.resolve(model)];
        }catch(e){}
    }
    private mount(model: string){
        try{
            require(model);
        }catch(e){
            console.log(`compile error ! file : ${model} error ` );
            console.log(e);
            return false;
        }
        return true;
    }
}

export default Watch